package com.example.ConditionHandlers;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.example.db.DBUpdaterHandler;
import com.example.priorityobserver.Observable;
import com.example.priorityobserver.Observer;
import com.example.singletones.SQLHelper;
import com.example.singletones.WebCommunicator;
import com.example.singletones.userSettings;

public class Conditions_Module extends Observable<Map<String, Object>>
		implements Observer<Map<String, Object>> {
	private List<JSONObject> mEventsToLookFor;
	private String[] mFastSyringSearchEventsToLookFor = null;
	private SQLiteDatabase db = null;
	private final SQLHelper mSQLHelper;
	public static final int ReadDBIntervalSize = 5;
	private static int ReadDBitirator = ReadDBIntervalSize;

	private static Conditions_Module instance = null;

	public static Conditions_Module getInstance() {
		if (instance == null) {
			instance = new Conditions_Module();
		}
		return instance;
	}

	protected Conditions_Module() {

		mSQLHelper = SQLHelper.getInstance();
		;
		db = mSQLHelper.getWritableDatabase();

		// db.execSQL("DELETE FROM `mainConditions`");
		// String[] query = new String[2];
		// query[0] =
		// "select (select count(*) from `MainEvents` where (`String_Message` like '%ELECTRICITY:%Charging%' and Time_Event > datetime(strftime('%s', 'now') - 1000,  'unixepoch')) and (select count(*) from `MainEvents` where `String_Message` like '%wired headset state connected: true%' and Time_Event > datetime(strftime('%s', 'now') - 1000,  'unixepoch')))";
		// query[1]="{\"media_button\":\"play\"}";
		// db.execSQL(
		// "INSERT INTO `mainConditions` (`condition`,`action`,`name`,`secondsTaskLength`,`lastPerformed`) VALUES (?,?,'firstcondition',7200,'0000')",
		// query);
		getConditions();
		getEventsList();
		// mHandler.removeCallbacks(mUpdateTimeTask);
		// mHandler.postDelayed(mUpdateTimeTask, 1000);

	}

	public void testTriggerConditionTesting(String SensorName) {
		for (int itirator = 0; itirator < mFastSyringSearchEventsToLookFor.length; itirator++) {
			if (mFastSyringSearchEventsToLookFor[itirator].toLowerCase()
					.indexOf(SensorName.toLowerCase()) > -1) {
				testCondition(itirator);
			}
		}

	}

	public void getEventsList() {
		db = mSQLHelper.getWritableDatabase();
		mEventsToLookFor = new ArrayList<JSONObject>();
		Cursor cursor = db
				.rawQuery(
						"select `condition`,`action`,`name`,`secondsTaskLength`,`lastPerformed`,`id` from `mainConditions`",
						null);
		while (cursor.moveToNext()) {
			JSONObject myJson = new JSONObject();
			try {
				myJson.put("condition", cursor.getString(0));
				myJson.put("action", cursor.getString(1));
				myJson.put("name", cursor.getString(2));
				myJson.put("secondsTaskLength", cursor.getString(3));
				myJson.put("lastPerformed", cursor.getString(4));
				myJson.put("id", cursor.getString(5));
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			mEventsToLookFor.add(myJson);
		}
		mFastSyringSearchEventsToLookFor = new String[mEventsToLookFor.size()];
		for (int itirator = 0; itirator < mEventsToLookFor.size(); itirator++) {

			try {
				mFastSyringSearchEventsToLookFor[itirator] = mEventsToLookFor
						.get(itirator).getString("condition");
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public boolean getConditions() {
		URL url;
		try {
			userSettings.getInstance();
			url = new URL("http://75.98.171.141/getConditions.php?user="
					+ userSettings.userData.getUserName() + "&pass="
					+ userSettings.userData.getPassword());
			URLConnection yc = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(
					yc.getInputStream()));
			String inputLine;
			String fullInput = "";
			while ((inputLine = in.readLine()) != null)
				fullInput = fullInput + inputLine;
			in.close();
			try {
				JSONObject jsonObj = new JSONObject(fullInput);
				JSONArray recs = jsonObj.getJSONArray("conditions");
				for (int i = 0; i < recs.length(); i++) {
					JSONObject rec = recs.getJSONObject(i);
					String[] myArgs = new String[6];
					myArgs[0] = rec.getString("userConditionID");
					myArgs[1] = rec.getString("condition");
					myArgs[1] = myArgs[1].replaceAll("(?six)\n$", "");
					myArgs[2] = rec.getString("action");
					myArgs[3] = rec.getString("name");
					myArgs[4] = rec.getString("secondsTaskLength");
					myArgs[5] = rec.getString("lastPerformed");
					db.execSQL(
							"replace into `mainConditions` (`id`,`condition`,`action`,`name`,`secondsTaskLength`,`lastPerformed`) VALUES (?,?,?,?,?,?) ",
							myArgs);
				}
				return true;
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

	}

	public void testCondition(int iterator) {

		JSONObject myJson = mEventsToLookFor.get(iterator);
		if (myJson.has("condition")) {
			Cursor cursor;
			try {
				if (myJson.has("secondsTaskLength")
						&& myJson.has("lastPerformed")
						&& ((System.currentTimeMillis() / 1000)
								- Integer.parseInt((String) myJson
										.get("secondsTaskLength")) > Integer
								.parseInt((String) myJson.get("lastPerformed")))) {
					String query = myJson.getString("condition").toString();
					query = assignParameters(query);
					cursor = db.rawQuery(query, null);
					while (cursor.moveToNext()) {
						if (Integer.parseInt(cursor.getString(0)) > 0) {
							// EventsToLookFor.remove(iterator);
							db = mSQLHelper.getWritableDatabase();
							String[] params = new String[2];
							params[0] = ""
									+ (System.currentTimeMillis() / 1000);
							params[1] = myJson.getString("id");
							db.rawQuery(
									"update `mainConditions` set `lastPerformed`=? where id=?",
									null);

							userSettings.getInstance();
							WebCommunicator.getInstance().getRequest(
									"http://75.98.171.141/updateConditionTime.php?user="
											+ userSettings.userData
													.getUserName()
											+ "&userConditionID="
											+ params[1]
											+ "&pass="
											+ userSettings.userData
													.getPassword()
											+ "&lastPerformed=" + params[0]);
							if ((myJson.has("action")) && (myJson.has("name"))) {

								ActionHandler.getInstance().performAction(
										myJson);
							}
						}
					}
				} else {
					// EventsToLookFor.remove(iterator);
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	public void lookForConditions() {
		db = mSQLHelper.getWritableDatabase();
		Log.d("test", "Condition Handler test");
		for (int iterator = 0; iterator < mEventsToLookFor.size(); iterator++) {
			testCondition(iterator);
		}
		if (ReadDBitirator == 0) {
			ReadDBitirator = ReadDBIntervalSize;
			getEventsList();
		} else {
			ReadDBitirator--;
		}
	}

	private String assignParameters(String query) {
		List<String> parameters = new Vector<String>();
		Pattern namePtrn = Pattern.compile("\\$(?:[^\\\\$]+|\\.)*\\$");
		Matcher nameMtchr = namePtrn.matcher(query);
		while (nameMtchr.find()) {
			String find = nameMtchr.group(0);
			parameters.add(find);
		}
		return DBUpdaterHandler.getInstance().assignParameters(query,
				parameters);
	}

	public void update(Observable<Map<String, Object>> o,
			Map<String, Object> arg) {
		if (arg.containsKey("sensorName")) {
			testTriggerConditionTesting(arg.get("sensorName").toString());
		}
	}
}
